import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { OrderStatus } from '../constants/order-status';
import { OrderType } from '../constants/order-type';
import { OrderModel } from '../models/order-model';
import { PlaceOrdersCommand } from '../models/place-orders-command';

@Injectable({
    providedIn: 'root',
})
export class OrderService {
    private orders = new BehaviorSubject<OrderModel[]>([]);
    private isLoading = new BehaviorSubject<boolean>(false);

    public orders$: Observable<OrderModel[]>;
    public isLoading$: Observable<boolean>;
    public isEmpty$: Observable<boolean>;

    public newOrderCount$: Observable<number>;
    public receivedOrderCount$: Observable<number>;
    public inProgressOrderCount$: Observable<number>;
    public finishedOrderCount$: Observable<number>;
    public totalOrderCount$: Observable<number>;

    constructor(private httpClient: HttpClient) {
        this.orders$ = this.orders
            .asObservable()
            .pipe(
                map((orders: OrderModel[]) =>
                    orders.sort((a, b) => b.dateCreated - a.dateCreated)
                )
            );

        this.isLoading$ = this.isLoading.asObservable();

        this.isEmpty$ = this.orders$.pipe(
            map((orders: OrderModel[]) => orders.length === 0)
        );

        this.newOrderCount$ = this.orders$.pipe(
            map(
                (orders: OrderModel[]) =>
                    orders.filter((order) => order.status === 'New').length
            )
        );

        this.receivedOrderCount$ = this.orders$.pipe(
            map(
                (orders: OrderModel[]) =>
                    orders.filter((order) => order.status === 'Received').length
            )
        );

        this.inProgressOrderCount$ = this.orders$.pipe(
            map(
                (orders: OrderModel[]) =>
                    orders.filter((order) => order.status === 'InProgress')
                        .length
            )
        );

        this.finishedOrderCount$ = this.orders$.pipe(
            map(
                (orders: OrderModel[]) =>
                    orders.filter((order) => order.status === 'Finished').length
            )
        );

        this.totalOrderCount$ = this.orders$.pipe(
            map((orders: OrderModel[]) => orders.length)
        );

        this.loadOrders();
    }

    private loadOrders() {
        var serializedOrders = localStorage.getItem('orders');
        if (serializedOrders) {
            var orders = JSON.parse(serializedOrders);
            this.orders.next(orders);
        } else {
            this.orders.next([]);
        }
    }

    private saveOrders() {
        localStorage.setItem('orders', JSON.stringify(this.orders.value));
    }

    placeOrders(type: OrderType, count: number) {
        if (count > 0) {
            var orders = this.orders.value;
            var newOrders: OrderModel[] = [];

            for (var i = 0; i < count; i++) {
                var order = new OrderModel(type);
                newOrders.push(order);
            }

            orders = orders.concat(newOrders);

            this.orders.next(orders);
            this.saveOrders();

            var command = new PlaceOrdersCommand();
            command.orders = newOrders;

            this.httpClient
                .post<OrderModel[]>('http://localhost:5000/api/orders', command)
                .subscribe((response: OrderModel[]) => {
                    response.forEach((newOrder) => {
                        this.updateOrderStatus(newOrder.id, newOrder.status);
                    });
                });
        }
    }

    clearOrders() {
        this.orders.next([]);
        this.saveOrders();
    }

    updateOrderStatus(orderId: string, status: OrderStatus) {
        var orders = this.orders.value;

        orders.forEach((order) => {
            if (order.id === orderId) {
                order.status = status;
                if (status === OrderStatus.Finished) {
                    order.dateFinished = new Date().getTime();
                }
            }
        });

        this.orders.next(orders);

        this.saveOrders();
    }
}
